/*
 * Copyright 2004-2007 Gary Bentley 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may 
 * not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 *    http://www.apache.org/licenses/LICENSE-2.0 
 *
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */
package org.sourceprojects.cappadocia.org.josql.functions.regexp;

import java.util.HashMap;
import java.util.Map;

import org.sourceprojects.cappadocia.org.josql.Query;
import org.sourceprojects.cappadocia.org.josql.QueryExecutionException;

public class RegExpFactory {

	/**
	 * The instance name to use for the Java 1.4 (java.util.regex) regular
	 * expression library. Whilst this is the default it will not be available
	 * on version of Java < 1.4.
	 */
	public static final String JAVA_INST = "java";

	/**
	 * The instance name to use for the ORO Apache regular expression library.
	 */
	public static final String ORO_INST = "oro";

	/**
	 * The instance name to use for the GNU regular expression library.
	 */
	public static final String GNU_INST = "gnu";

	/**
	 * The instance name to use for the Apache RegExp regular expression
	 * library.
	 */
	public static final String APACHE_REGEXP_INST = "apache.regexp";

	private String defInst = RegExpFactory.JAVA_INST;

	private final Map mappings = new HashMap();
	private final Map versions = new HashMap();

	public RegExpFactory(final Query q) {

		final StandardJavaRegExpWrapper j = new StandardJavaRegExpWrapper();

		if (j.isAvailable(q)) {

			this.mappings.put(RegExpFactory.JAVA_INST,
					StandardJavaRegExpWrapper.class);
			this.versions.put(RegExpFactory.JAVA_INST, j.getSupportedVersion());

		}

		final OroApacheRegExpWrapper o = new OroApacheRegExpWrapper();

		if (o.isAvailable(q)) {

			this.mappings.put(RegExpFactory.ORO_INST,
					OroApacheRegExpWrapper.class);
			this.versions.put(RegExpFactory.ORO_INST, o.getSupportedVersion());

		}

		final GNURegExpWrapper g = new GNURegExpWrapper();

		if (g.isAvailable(q)) {

			this.mappings.put(RegExpFactory.GNU_INST, GNURegExpWrapper.class);
			this.versions.put(RegExpFactory.GNU_INST, g.getSupportedVersion());

		}

		final ApacheRegExpWrapper a = new ApacheRegExpWrapper();

		if (a.isAvailable(q)) {

			this.mappings.put(RegExpFactory.APACHE_REGEXP_INST,
					ApacheRegExpWrapper.class);
			this.versions.put(RegExpFactory.APACHE_REGEXP_INST,
					a.getSupportedVersion());

		}

	}

	public String getSupportedVersion(final String instName) {

		return (String) this.versions.get(instName);

	}

	public String getDefaultInstanceName() {

		return this.defInst;

	}

	public void addInstance(final String name, final RegExp re,
			final boolean def) {

		this.mappings.put(name, re);

		if (def) {

			this.defInst = name;

		}

	}

	public void setDefaultInstanceName(final String n) {

		if (!this.mappings.containsKey(n)) {

			throw new IllegalArgumentException(
					"No appropriate wrapper class found for instance name: "
							+ n);

		}

		this.defInst = n;

	}

	public RegExp getDefaultInstance(final Query q)
			throws QueryExecutionException {

		return this.getInstance(this.defInst, q);

	}

	public RegExp getInstance(final String type, final Query q)
			throws QueryExecutionException {

		final Object o = this.mappings.get(type);

		if (o == null) {

			return null;

		}

		if (o instanceof RegExp) {

			// Already inited...
			return (RegExp) o;

		}

		final Class c = (Class) o;

		try {

			final RegExp re = (RegExp) c.newInstance();

			re.init(q);

			this.mappings.put(type, re);

			return re;

		} catch (final Exception e) {

			throw new QueryExecutionException(
					"Unable to init RegExp instance: " + c.getName(), e);

		}

	}

}
